package org.dromara.system.kernel.channel;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.encrypt.utils.EncryptUtils;
import org.dromara.system.domain.PayAccount;
import org.dromara.system.domain.PayGroupAccount;
import org.dromara.system.domain.PayOrder;
import org.dromara.system.domain.PayOrderLog;
import org.dromara.system.domain.bo.aparams.AOrderBo;
import org.dromara.system.domain.bo.cparams.OrderProduct;
import org.dromara.system.domain.bo.cparams.OrderUpdateBo;
import org.dromara.system.domain.bo.xiangpay.XiangPushBo;
import org.dromara.system.domain.bo.xiangpay.XiangUpdateBo;
import org.dromara.system.kernel.OrderUpdateKernel;
import org.dromara.system.service.IPayAccountService;
import org.dromara.system.service.IPayOrderLogService;
import org.dromara.system.service.IPayOrderService;
import org.dromara.system.utils.ConversionUtils;
import org.dromara.system.utils.RequestUtils;
import org.dromara.system.utils.UserAgentUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@RequiredArgsConstructor
@Service
public class XiangPayOrderKernel {

    private final IPayOrderLogService orderLogService;
    private final IPayOrderService orderService;
    private final IPayOrderService payOrderService;
    private final OrderUpdateKernel orderUpdateKernel;
    private final IPayAccountService accountService;
    @Value("${gatewayDomain}")
    public String gatewayDomain;

    /**
     * 获取支付链接
     *
     * @param account      收款账号
     * @param groupAccount 轮询组收款账号配置
     * @param order        订单信息
     */
    public R<PayOrder> requestPayLink(PayAccount account, PayGroupAccount groupAccount, PayOrder order, PayOrderLog log) {

        //获取账号请求域名
        String domain = account.getDomain();
        if (StringUtils.isEmpty(domain)) {
            return R.fail("DomainUrl is invalid", order);
        }

        //获取账号配置
        JSONObject config = account.getAccountConfig();
        if (!config.containsKey("clientId") || !config.containsKey("secretKey") || !config.containsKey("checkApi") || !config.containsKey("createApi")) {
            return R.fail("Account Config is invalid", order);
        }
        String clientId = config.getString("clientId"); //商户ID
        String secretKey = config.getString("secretKey"); //商户密匙
        String checkApi = config.getString("checkApi"); //判断通道是否可用】接口API
        String createApi = config.getString("createApi"); //推送订单】接口API

        //判断通道是否可用
        long time = System.currentTimeMillis();
        Map<String, String> header = new HashMap<>();
        header.put("client_id", clientId);
        header.put("secret_key", secretKey);
        String jsonStr = new JSONObject().fluentPut("domain", gatewayDomain.replace("https://", "")).fluentPut("type", "credit").fluentPut("client_id", clientId).toJSONString();
        String res = new RequestUtils().doPostJson(domain + checkApi, jsonStr, header);
        //记录请求日志
        orderLogService.saveLog(log.getLogId(), order.getOrderId(), order.getOrderNo(), order.getOrderAid(), "检测通道是否可用", jsonStr, res, System.currentTimeMillis() - time);

        if (StringUtils.isEmpty(res)) {
            return R.fail("companychannel check failed", order);
        }
        //解析返回参数
        Integer model;
        Integer bid = null;
        try {
            JSONObject result = JSONObject.parseObject(res);
            if (result.getInteger("code") != 1) {
                return R.fail(result.getString("info"), order);
            }
            JSONObject data = result.getJSONObject("data");
            model = data.getInteger("model");
            bid = data.getInteger("bid");
        } catch (Exception e) {
            return R.fail("companychannel check failed!", order);
        }

        //为 1 时, 说明通道为跳转 (不需要回传 bid), 第二步接口创建订单成功后 你们需要跳到我们给的链接
        //为 2 时, 第二步接口 需要传信用卡信息 以及 bid, 如果第二步返回的data不为空 则跳到 data页面, 没值则跳到订单已接收页面
        //为 5 时, 第二步接口 需要传信用卡信息 以及 bid, 然后跳到我们返回给你的链接(data)
        //如果要传卡，就得接直连内嵌，目前只接入直接调整链接
        if (model != 1) {
            return R.fail("companychannel model is not available", order);
        }

        //构建参数
        JSONObject params = buildParams(groupAccount, order, clientId, secretKey);
        if (params == null) {
            return R.fail("no config params found", order);
        }

        //请求
        time = System.currentTimeMillis();
        String res1;
        try {
            res1 = new RequestUtils().doPostJsonNoTry(domain + createApi, params.toJSONString());
        } catch (Exception e) {
            res1 = "请求失败：" + e.getMessage();
        }

        //记录请求日志
        orderLogService.saveLog(log.getLogId(), order.getOrderId(), order.getOrderNo(), order.getOrderAid(), "获取支付链接", params.toString(JSONWriter.Feature.WriteMapNullValue), res1, System.currentTimeMillis() - time);

        try {
            if (StringUtils.isEmpty(res1) || res1.startsWith("请求失败")) {
                return R.fail("Request link null", order);
            }

            //解析返回参数
            JSONObject result;
            try {
                result = JSONObject.parseObject(res1);
            } catch (Exception e) {
                return R.fail(res1, order);
            }

            if (!Objects.equals(result.getInteger("code"), 1)) {
                return R.fail(result.getString("info"), order);
            }

            String payUrl = result.getString("data");

            //写到订单对象里，返出去使用
            order.setLink(payUrl);

            //更新订单
            PayOrder up = new PayOrder();
            up.setOrderId(order.getOrderId());
            up.setLink(payUrl);
            orderService.updatePayOrderAsync(up);

            //记录更新日志
            orderLogService.saveLog(log.getLogId(), order.getOrderId(), order.getOrderNo(), order.getOrderAid(), "更新B端订单信息", JSONObject.toJSONString(up), "success", 10L);

            return R.ok(order);

        } catch (Exception e) {
            return R.fail("Request link fail", order);
        }
    }

    /**
     * 更新订单
     *
     * @param cBo 参数
     * @return JSONObject
     */
    public R<?> updateOrder(XiangUpdateBo cBo) {

        if (StringUtils.isEmpty(cBo.getOrderId()) || cBo.getStatus() == null || StringUtils.isEmpty(cBo.getSign()) || StringUtils.isEmpty(cBo.getSecret_key())) {
            return R.fail("params is valid");
        }

        Long orderId = Long.parseLong(cBo.getOrderId().split("_")[0]);
        Integer code = cBo.getStatus();
        if (code != 0 && code != 1) {
            return R.ok();
        }

        PayOrder order = payOrderService.selectById(orderId);
        if (order == null) {
            return R.fail("Order does not exist");
        }

        //获取账号配置
        PayAccount account = accountService.selectById(order.getAccountId());
        if (account != null) {
            //获取账号配置
            JSONObject config = account.getAccountConfig();
            if (config.containsKey("clientId")) {
                String clientId = config.getString("clientId");
                String sign = EncryptUtils.encryptByMd5(cBo.getSecret_key() + cBo.getOrderId() + clientId);
                if (!Objects.equals(sign, cBo.getSign())) {
                    return R.fail("sign is invalid");
                }
            }
        }

        //更新订单参数
        OrderUpdateBo bo = new OrderUpdateBo(orderId, code == 1 ? 2 : 3, null);

        //更新订单
        return orderUpdateKernel.updateOrder(order, bo, JSONObject.toJSONString(cBo));
    }

    /**
     * 构建请求参数
     *
     * @param order 订单
     * @return JSONObject
     */
    private JSONObject buildParams(PayGroupAccount groupAccount, PayOrder order, String clientId, String secretKey) {

        String currency; //币别
        BigDecimal amount; //金额
        if (Objects.equals(groupAccount.getIsForce(), 1) && order.getForceCurrency() != null) {
            currency = order.getForceCurrency();
            amount = order.getForceMoney();
        } else {
            currency = order.getCurrency();
            amount = order.getCMoney();
        }

        amount = amount.setScale(2, RoundingMode.HALF_UP);

        AOrderBo.Address bill = JSONObject.parseObject(order.getCustomer(), AOrderBo.Address.class);
        AOrderBo.Address shipping = JSONObject.parseObject(order.getShipping(), AOrderBo.Address.class);

        //订单信息
        XiangPushBo.Info info = new XiangPushBo.Info();
        info.setOid(order.getOrderId() + "_" + ConversionUtils.generateShortCode(order.getOrderId() + "", 14));
        info.setDatetime(System.currentTimeMillis() / 1000);
        info.setTotal(amount.toPlainString());
        info.setCurrency(currency);
        info.setCountry(bill.getCountry());
        info.setPayment_type("credit");
        info.setEmail(order.getCustomerEmail());
        info.setSecret_key(secretKey);
        info.setUseragent(UserAgentUtils.getUserAgent());
        info.setLanguage("en");
        info.setDomain(gatewayDomain);
        info.setReturn_url(order.getSuccessUrl());
        info.setCancel_url(order.getCancelUrl());
        info.setNotify_url(gatewayDomain + "/api/system/external/updateXiang");
        info.setCustomer_ip(order.getCustomerIp());
        info.setModel(1);

        //产品信息
        List<XiangPushBo.Product> prods = new ArrayList<>();
        List<OrderProduct> products = JSONArray.parseArray(order.getProduct(), OrderProduct.class);
        for (OrderProduct product : products) {
            XiangPushBo.Product obj = new XiangPushBo.Product();
            obj.setName(product.getName());
            obj.setImage(product.getImage());
            obj.setAttribute(product.getAttributes());
            obj.setQty(product.getQuantity());
            obj.setPrice(product.getPrice());
            obj.setLink(product.getImage());
            prods.add(obj);
        }

        //账单地址
        XiangPushBo.Address billAddress = new XiangPushBo.Address();
        billAddress.setFirstname(bill.getFirstName());
        billAddress.setLastname(bill.getLastName());
        billAddress.setAddress1(bill.getAddress1());
        billAddress.setAddress2(bill.getAddress2());
        billAddress.setCity(bill.getCity());
        billAddress.setState(bill.getState());
        billAddress.setZip(bill.getPostcode());
        billAddress.setCountry(bill.getCountry());
        billAddress.setPhone(bill.getPhone());

        //送货地址
        XiangPushBo.Address shipAddress = new XiangPushBo.Address();
        shipAddress.setFirstname(shipping.getFirstName());
        shipAddress.setLastname(shipping.getLastName());
        shipAddress.setAddress1(shipping.getAddress1());
        shipAddress.setAddress2(shipping.getAddress2());
        shipAddress.setCity(shipping.getCity());
        shipAddress.setState(shipping.getState());
        shipAddress.setZip(shipping.getPostcode());
        shipAddress.setCountry(shipping.getCountry());
        shipAddress.setPhone(shipping.getPhone());

        // 构建签名
        // * $hash = hash('sha256', $secret_key . $info['email'] . $info['currency'] . $info['total'] . $info['country']);
        // * $sign = md5($hash . $client_id);
        String hash = EncryptUtils.encryptBySha256(secretKey + info.getEmail() + info.getCurrency() + info.getTotal() + info.getCountry());
        String sign = EncryptUtils.encryptByMd5(hash + clientId);

        //构建参数
        XiangPushBo bo = new XiangPushBo();
        bo.setBilling(billAddress);
        bo.setDelivery(shipAddress);
        bo.setProducts(prods);
        bo.setInfo(info);
        bo.setSign(sign);

        return JSONObject.from(bo, JSONWriter.Feature.WriteMapNullValue);
    }
}
